﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Joy.Erp.BasicArchives.Staff;
using Joy.Erp.Ufida.Core;
using Microsoft.Extensions.Logging;

namespace Joy.Erp.Ufida.Staff
{
    public class DepartmentSyncAppService : UfidaAppService, IDepartmentSyncAppService
    {
        protected IDepartmentRepository DepartmentRepository => LazyServiceProvider.LazyGetRequiredService<IDepartmentRepository>();
        protected IDepartmentAppService DepartmentAppService => LazyServiceProvider.LazyGetRequiredService<IDepartmentAppService>();
        protected IDepartmentUfidaAppService DepartmentUfidaAppService => LazyServiceProvider.LazyGetRequiredService<IDepartmentUfidaAppService>();
        protected DepartmentManager DepartmentManager => LazyServiceProvider.LazyGetRequiredService<DepartmentManager>();

        public async Task<AnalysisDto> Analyze‌Async()
        {
            var analysisDto = new AnalysisDto();
            analysisDto.Id = typeof(Department).FullName;

            // 获取U9数据的ID列表
            var u9list = await DepartmentUfidaAppService.GetAllAsync();
            var u9Ids = u9list.Select(x => x.ID.ToString()).ToHashSet();
            analysisDto.U9Count = u9Ids.Count;

            // 使用数据库查询优化，只查询需要的字段
            var pmcQuery = await DepartmentRepository.GetQueryableAsync();

            // 获取PMC总数
            analysisDto.Count = await AsyncExecuter.CountAsync(pmcQuery.Where(x => !x.IsDeleted));

            // 获取已同步的SourceKey列表
            var syncedSourceKeys = await AsyncExecuter.ToListAsync(
                pmcQuery
                    .Where(x => !x.IsDeleted && x.SourceType == SourceConfig.SourceType)
                    .Select(x => x.SourceKey)
            );

            // 使用 HashSet 快速计算已同步数量
            analysisDto.AsyncCount = syncedSourceKeys.Count(key => u9Ids.Contains(key));
            analysisDto.UnasyncCount = analysisDto.U9Count - analysisDto.AsyncCount;
            analysisDto.SelfCount = analysisDto.Count - analysisDto.AsyncCount;

            return analysisDto;
        }

        public async Task<List<long>> GetUnasyncIds()
        {
            // 获取U9的所有ID
            var u9list = await DepartmentUfidaAppService.GetAllAsync();
            var u9Ids = u9list.Select(x => x.ID).ToList();

            // 使用数据库查询，只查询已同步的SourceKey
            var pmcQuery = await DepartmentRepository.GetQueryableAsync();
            var syncedSourceKeys = await AsyncExecuter.ToListAsync(
                pmcQuery
                    .Where(x => !x.IsDeleted && x.SourceType == SourceConfig.SourceType)
                    .Select(x => x.SourceKey)
            );

            // 使用 HashSet 优化查找性能，时间复杂度从 O(n²) 降到 O(n)
            var syncedSourceKeySet = new HashSet<string>(syncedSourceKeys);

            // 找出未同步的ID
            var unasyncIds = u9Ids
                .Where(id => !syncedSourceKeySet.Contains(id.ToString()))
                .ToList();

            return unasyncIds;
        }

        public async Task<int> CreateByIds‌Async(long[] ids)
        {
            if (ids == null || ids.Length == 0)
                return 0;

            // 批量预查询已存在的记录，避免循环查询数据库
            var pmcQuery = await DepartmentRepository.GetQueryableAsync();
            var idStrings = ids.Select(id => id.ToString()).ToList();
            var existingSourceKeys = await AsyncExecuter.ToListAsync(
                pmcQuery
                    .Where(x =>
                        idStrings.Contains(x.SourceKey) && x.SourceType == SourceConfig.SourceType
                    )
                    .Select(x => x.SourceKey)
            );
            var existingSet = new HashSet<string>(existingSourceKeys);

            // 过滤出需要创建的ID
            var needCreateIds = ids.Where(id => !existingSet.Contains(id.ToString())).ToList();
            if (needCreateIds.Count == 0)
                return ids.Length;

            Logger.LogInformation($"[批量同步-部门] 开始处理 {needCreateIds.Count} 条新增，已存在 {existingSet.Count} 条");

            // 为了确保父级先于子级创建，需要先加载所有父级部门数据
            var allU9DataDict = await LoadDepartmentsWithParents(needCreateIds, existingSet);
            if (allU9DataDict.Count == 0) return existingSet.Count;

            // 按层级排序，确保父级先于子级创建（通过ParentNode关系计算层级）
            var sortedList = allU9DataDict.OrderBy(kvp => GetDepartmentLevel(kvp.Value, allU9DataDict)).ToList();

            var successCount = 0;
            using (var uow = UnitOfWorkManager.Begin(new Volo.Abp.Uow.AbpUnitOfWorkOptions(), requiresNew: true))
            {
                try
                {
                    foreach (var (id, dto) in sortedList)
                    {
                        try
                        {
                            var result = await CreateByIdAsync(id);
                            if (result)
                            {
                                successCount++;
                            }
                        }
                        catch (Exception ex)
                        {
                            Logger.LogWarning(ex, $"[批量同步-部门] 创建实体失败，Id: {id}");
                        }
                    }

                    await uow.CompleteAsync();
                }
                catch (Exception ex)
                {
                    Logger.LogWarning(ex, $"[批量同步-部门] 批量创建失败，{ex.Message}");
                }
            }

            Logger.LogInformation($"[批量同步-部门] 完成！成功新增 {successCount} 条，总计 {successCount + existingSet.Count} 条");

            return successCount + existingSet.Count;
        }

        public async Task<List<long>> GetSyncedIds()
        {
            var pmcQuery = await DepartmentRepository.GetQueryableAsync();
            var syncedSourceKeys = await AsyncExecuter.ToListAsync(
                pmcQuery
                    .Where(x => !x.IsDeleted && x.SourceType == SourceConfig.SourceType)
                    .Select(x => x.SourceKey)
            );
            return syncedSourceKeys
                .Select(key => long.Parse(key))
                .ToList();
        }

        public async Task<int> UpdateByIdsAsync(long[] ids)
        {
            if (ids == null || ids.Length == 0) return 0;

            Logger.LogInformation($"[批量同步-部门] 开始处理 {ids.Length} 条更新");
            var pmcQuery = await DepartmentRepository.GetQueryableAsync();
            var idStrings = ids.Select(id => id.ToString()).ToList();
            var existingEntities = await AsyncExecuter.ToListAsync(
                pmcQuery.Where(x =>
                    idStrings.Contains(x.SourceKey) && x.SourceType == SourceConfig.SourceType
                )
            );
            if (existingEntities.Count == 0)
            {
                Logger.LogWarning($"[批量同步-部门] 没有找到需要更新或删除的记录");
                return 0;
            }
            var entityDict = existingEntities.ToDictionary(x => x.SourceKey, x => x);
            var allU9DataDict = new Dictionary<long, DepartmentUfidaDto>();
            foreach (var id in ids)
            {
                if (!entityDict.ContainsKey(id.ToString())) continue;

                try
                {
                    var dto = await DepartmentUfidaAppService.GetAsync(id);
                    if (dto != null) allU9DataDict[id] = dto;
                }
                catch (Exception ex)
                {
                    Logger.LogWarning(ex, $"[批量同步-部门] 获取U9数据失败，Id: {id}");
                }
            }

            var parentSourceKeys = allU9DataDict.Values
                .Where(x => x.ParentNode.HasValue)
                .Select(x => x.ParentNode.Value.ToString())
                .Where(parentKey => !entityDict.ContainsKey(parentKey))
                .Distinct()
                .ToList();
            var parentCacheDict = await BatchLoadDepartments(parentSourceKeys);

            var entitiesToUpdate = new List<Department>();
            var entitiesToDelete = new List<Department>();
            foreach (var id in ids)
            {
                try
                {
                    var key = id.ToString();
                    if (!entityDict.TryGetValue(key, out var entity)) continue;

                    if (!allU9DataDict.TryGetValue(id, out var u9Data))
                    {
                        entitiesToDelete.Add(entity);
                        continue;
                    }

                    entity.DisplayName = u9Data.Name;
                    //entity.Code = u9Data.Code;   树结构的Code在pmc中不能赋值
                    entity.SourceCreatedOn = u9Data.CreatedOn;
                    entity.ParentId = null;
                    entity.Level = 1;

                    if (u9Data.ParentNode.HasValue)
                    {
                        var parentKey = u9Data.ParentNode.Value.ToString();
                        if (entityDict.TryGetValue(parentKey, out var parentEntity))
                        {
                            entity.ParentId = parentEntity.Id;
                            entity.Level = parentEntity.Level + 1;
                        }
                        else if (parentCacheDict.TryGetValue(parentKey, out var parentDto))
                        {
                            entity.ParentId = parentDto.Id;
                            entity.Level = parentDto.Level + 1;
                        }
                        else
                        {
                            Logger.LogWarning($"[批量同步-部门] 未找到父级部门，SourceKey: {parentKey}");
                        }
                    }

                    entitiesToUpdate.Add(entity);
                }
                catch (Exception ex)
                {
                    Logger.LogWarning(ex, $"[批量同步-部门] 修改实体失败，Id: {id}");
                }
            }

            if (entitiesToUpdate.Count == 0 && entitiesToDelete.Count == 0)
            {
                Logger.LogInformation($"[批量同步-部门] 无需更新或删除记录");
                return 0;
            }

            var updateCount = 0;
            var deleteCount = 0;
            using (var uow = UnitOfWorkManager.Begin(new Volo.Abp.Uow.AbpUnitOfWorkOptions(), requiresNew: true))
            {
                try
                {
                    if (entitiesToUpdate.Count > 0)
                    {
                        await DepartmentRepository.BulkUpdateAsync(
                            entitiesToUpdate,
                            autoSave: false
                        );
                        updateCount = entitiesToUpdate.Count;
                    }

                    if (entitiesToDelete.Count > 0)
                    {
                        await DepartmentRepository.BulkDeleteAsync(
                            entitiesToDelete,
                            autoSave: false
                        );
                        deleteCount = entitiesToDelete.Count;
                    }

                    await uow.CompleteAsync();
                }
                catch (Exception ex)
                {
                    Logger.LogWarning(ex, $"[批量同步-部门] 批量更新/删除失败，{ex.Message}");
                }
            }

            Logger.LogInformation($"[批量同步-部门] 完成！成功更新 {updateCount} 条，删除 {deleteCount} 条");
            return updateCount + deleteCount;
        }

        private async Task<Dictionary<long, DepartmentUfidaDto>> LoadDepartmentsWithParents(List<long> ids, HashSet<string> existingSourceKeys)
        {
            var result = new Dictionary<long, DepartmentUfidaDto>();
            if (ids == null || ids.Count == 0)
                return result;

            var stack = new Stack<long>(ids);
            while (stack.Count > 0)
            {
                var currentId = stack.Pop();
                var sourceKey = currentId.ToString();

                if (existingSourceKeys.Contains(sourceKey) || result.ContainsKey(currentId))
                    continue;

                DepartmentUfidaDto dto = null;
                try
                {
                    dto = await DepartmentUfidaAppService.GetAsync(currentId);
                }
                catch (Exception ex)
                {
                    Logger.LogWarning(ex, $"[批量同步-部门] 获取U9数据失败，Id: {currentId}");
                }

                if (dto == null)
                    continue;

                result[currentId] = dto;

                if (
                    dto.ParentNode.HasValue
                    && !existingSourceKeys.Contains(dto.ParentNode.Value.ToString())
                    && !result.ContainsKey(dto.ParentNode.Value)
                )
                {
                    stack.Push(dto.ParentNode.Value);
                }
            }

            return result;
        }

        private async Task<bool> CreateByIdAsync(long id)
        {
            var existDepartment = await DepartmentAppService.FindBySourceKeyAsync(id.ToString(), SourceConfig.SourceType);
            if (existDepartment != null) return true;

            var departmentUfidaDto = await DepartmentUfidaAppService.GetAsync(id);
            if (departmentUfidaDto == null) return false;

            try
            {
                await CreateAsync(departmentUfidaDto);
                return true;
            }
            catch (Exception ex)
            {
                Logger.LogWarning(ex, $"CreateByIdAsync 创建失败，Id: {id}, 错误信息：{ex.Message}");
                return false;
            }
        }

        private async Task<DepartmentDto> CreateAsync(DepartmentUfidaDto departmentUfidaDto)
        {
            var departmentCreateDto = new DepartmentCreateDto();
            departmentCreateDto.SourceType = SourceConfig.SourceType;
            departmentCreateDto.SourceKey = departmentUfidaDto.ID.ToString();
            departmentCreateDto.DisplayName = departmentUfidaDto.Name;
            departmentCreateDto.SourceCreatedOn = departmentUfidaDto.CreatedOn;
            departmentCreateDto.ParentId = null;
            //Code = departmentUfidaDto.Code,   树结构的Code在pmc中不能赋值，由CreateAsync自动生成

            // 处理父级关系
            if (departmentUfidaDto.ParentNode.HasValue)
            {
                var parentDepartment = await DepartmentAppService.FindBySourceKeyAsync(
                    departmentUfidaDto.ParentNode.Value.ToString(),
                    SourceConfig.SourceType
                );
                if (parentDepartment == null)
                {
                    // 如果父级不存在，递归创建父级
                    var parentUfidaDto = await DepartmentUfidaAppService.GetAsync(departmentUfidaDto.ParentNode.Value);
                    if (parentUfidaDto != null)
                    {
                        parentDepartment = await CreateAsync(parentUfidaDto);
                    }
                }
                if (parentDepartment != null)
                {
                    departmentCreateDto.ParentId = parentDepartment.Id;
                }
            }

            return await DepartmentAppService.CreateAsync(departmentCreateDto);
        }

        /// <summary>
        /// 计算部门的层级（用于排序）
        /// </summary>
        private int GetDepartmentLevel(DepartmentUfidaDto dto, Dictionary<long, DepartmentUfidaDto> allU9DataDict)
        {
            if (!dto.ParentNode.HasValue)
                return 1;

            var level = 1;
            var currentParentId = dto.ParentNode.Value;
            var visited = new HashSet<long> { dto.ID };

            while (!visited.Contains(currentParentId))
            {
                visited.Add(currentParentId);
                level++;
                if (allU9DataDict.TryGetValue(currentParentId, out var parentDto) && parentDto.ParentNode.HasValue)
                {
                    currentParentId = parentDto.ParentNode.Value;
                }
                else
                {
                    break;
                }
            }

            return level;
        }

        private async Task<Dictionary<string, DepartmentDto>> BatchLoadDepartments(List<string> sourceKeys)
        {
            if (sourceKeys == null || sourceKeys.Count == 0) return new Dictionary<string, DepartmentDto>();

            var query = await DepartmentRepository.GetQueryableAsync();
            var items = await AsyncExecuter.ToListAsync(
                query.Where(x =>
                    sourceKeys.Contains(x.SourceKey) && x.SourceType == SourceConfig.SourceType
                )
            );
            return items.ToDictionary(
                x => x.SourceKey,
                x => ObjectMapper.Map<Department, DepartmentDto>(x)
            );
        }
    }
}
